<?php

namespace App\Service;


use Psr\Http\Message\ServerRequestInterface;
use Hyperf\Context\Context;
use function Hyperf\Config\config;

class ToolService {
    /**
     * 构建不转义的query串
     * @param $post
     * @return string
     */
    public static function buildQueryStr($post): string {
        $return = [];
        ksort($post);
        foreach ($post as $key => $value) {
            $return[] = "{$key}={$value}";
        }

        return implode('&', $return);
    }

    /**
     * 二次封装的密码加密
     * @param string $str
     * @param string $auth_key
     * @return string
     * @author zhaoxiang <zhaoxiang051405@gmail.com>
     */
    public static function userMd5(string $str, string $auth_key = ''): string {
        if (!$auth_key) {
            $auth_key = 'ApiAdmin';
        }

        return '' === $str ? '' : md5(sha1($str) . $auth_key);
    }

    /**
     * 判断当前用户是否是超级管理员
     * @param int $uid
     * @return bool
     * @author zhaoxiang <zhaoxiang051405@gmail.com>
     */
    public static function isAdministrator(int $uid = 0): bool {
        if (!empty($uid)) {
            $adminConf = config('apiadmin.user_administrator');
            if (in_array($uid, $adminConf)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 将查询的二维对象转换成二维数组
     * @param $res
     * @param string $key 允许指定索引值
     * @return array
     * @author zhaoxiang <zhaoxiang051405@gmail.com>
     */
    public static function buildArrFromObj($res, string $key = ''): array {
        $arr = [];
        if ($res) {
            foreach ($res as $value) {
                $value = $value->toArray();
                if ($key) {
                    $arr[$value[$key]] = $value;
                } else {
                    $arr[] = $value;
                }
            }
        }

        return $arr;
    }

    /**
     * 将二维数组变成指定key
     * @param $array
     * @param string $keyName
     * @return array
     * @author zhaoxiang <zhaoxiang051405@gmail.com>
     */
    public static function buildArrByNewKey($array, string $keyName = 'id'): array {
        $list = [];
        foreach ($array as $item) {
            $list[$item[$keyName]] = $item;
        }

        return $list;
    }

    /**
     * 把返回的数据集转换成Tree
     * @param array $list
     * @param string $pk
     * @param string $pid
     * @param string $child
     * @param string $root
     * @return array
     */
    public static function listToTree(
        array  $list,
        string $pk = 'id',
        string $pid = 'fid',
        string $child = 'children',
        string $root = '0'
    ): array {
        $result = [];

        foreach ($list as &$item) {
            if ($item[$pid] == $root) {
                $allChildren = self::listToTree($list, $pk, $pid, $child, $item[$pk]);
                if (!empty($allChildren)) {
                    $item[$child] = $allChildren;
                }
                $result[] = $item;
            }
        }

        return $result;
    }

    /**
     * 将层级数组遍历成一维数组
     * @param array $list
     * @param int $lv
     * @param string $title
     * @return array
     * @author zhaoxiang <zhaoxiang051405@gmail.com>
     */
    public static function formatTree(array $list, int $lv = 0, string $title = 'title'): array {
        $formatTree = [];
        foreach ($list as $key => $val) {
            $title_prefix      = str_repeat("|---", $lv);
            $val['lv']         = $lv;
            $val['namePrefix'] = $lv === 0 ? '' : $title_prefix;
            $val['showName']   = $lv === 0 ? $val[$title] : $title_prefix . $val[$title];
            if (!array_key_exists('children', $val)) {
                $formatTree[] = $val;
            } else {
                $child = $val['children'];
                unset($val['children']);
                $formatTree[] = $val;
                $middle       = self::formatTree($child, $lv + 1, $title); //进行下一层递归
                $formatTree   = array_merge($formatTree, $middle);
            }
        }

        return $formatTree;
    }

    /**
     * 产生随机字串，可用来自动生成密码
     * 默认长度6位 字母和数字混合 支持中文
     * @param integer $len 长度
     * @param int $type 字串类型
     * 0 字母 1 数字 其它 混合
     * @param string $addChars 额外字符
     * @return string
     */
    public static function randString(int $len = 6, int $type = 0, string $addChars = ''): string {
        $chars = match ($type) {
            0 => 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' . $addChars,
            1 => str_repeat('0123456789', 3),
            2 => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' . $addChars,
            3 => 'abcdefghijklmnopqrstuvwxyz' . $addChars,
            default => 'ABCDEFGHIJKMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789' . $addChars,
        };
        if ($len > 10) {//位数过长重复字符串一定次数
            $chars = $type === 1 ? str_repeat($chars, $len) : str_repeat($chars, 5);
        }
        $chars = str_shuffle($chars);

        return substr($chars, 0, $len);
    }

    /**
     * 构建扣减数组，用户转换数据表配置的消耗道具
     * @param string $data [2_1001_1000]
     * @return array
     */
    public static function buildRemoveItemData(string $data): array {
        $removeItemArr = [];
        $itemArr       = explode(',', substr($data, 1, -1));
        foreach ($itemArr as $itemEach) {
            if ($itemEach) {
                [$type, $itemId, $num] = explode('_', $itemEach);
                $removeItemArr[] = [
                    'item_id' => $itemId,
                    'number'  => $num
                ];
            }
        }

        return $removeItemArr;
    }

    /**
     * 非对称加密
     * @param $data
     * @return mixed
     */
    public static function getEncryptedData($data): mixed {
        $privateKey = file_get_contents(BASE_PATH . '/my_pub_key.txt');
        $ok         = openssl_public_encrypt($data, $encryptedData, $privateKey);
        if ($ok) {
            $encryptedData = base64_encode($encryptedData);
        }

        return $encryptedData;
    }

    /**
     * 获取当期毫秒数
     * @return float
     */
    public static function getMicroTime(): float {
        list($micro, $sec) = explode(' ', microtime());

        return (float)sprintf('%.0f', (floatval($micro) + floatval($sec)) * 1000);
    }

    /**
     * 获取客户端IP
     * @return mixed|string
     */
    public function getClientIp(): mixed {
        /**
         * @var ServerRequestInterface $request
         */
        $request = Context::get(ServerRequestInterface::class);
        $ip_addr = $request->getHeaderLine('x-forwarded-for');
        if (filter_var($ip_addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
            return $ip_addr;
        }
        $ip_addr = $request->getHeaderLine('remote-host');
        if (filter_var($ip_addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
            return $ip_addr;
        }
        $ip_addr = $request->getHeaderLine('x-real-ip');
        if (filter_var($ip_addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
            return $ip_addr;
        }
        $ip_addr = $request->getServerParams()['remote_addr'] ?? '0.0.0.0';
        if (filter_var($ip_addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
            return $ip_addr;
        }
        return '0.0.0.0';
    }
}
